/*###################################################################
  > File Name: ylib/lib/rate_probe.c
  > Author: Vurtune
  > Mail: vurtune@foxmail.com
  > Created Time: Thu 18 May 2017 08:10:19 PM PDT
###################################################################*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define DBG_SUBSYS S_LIBSTORAGE
#define USECONDS_PER_SEC (1000000)

#include "adt.h"
#include "sysy_lib.h"
#include "ytime.h"
#include "rate_probe.h"


int rate_probe_init(rate_probe_t* probe, uint64_t compute_unit)
{
        int ret;

        ret = sy_rwlock_init(&probe->lock, "rate_probe.lock");
        if (unlikely(ret)) {
                GOTO(err_ret, ret);
        }

        probe->rate = 0;
        probe->tally = 0;
        probe->unit = compute_unit;
        probe->useconds = ytime_gettime();

        return 0;
err_ret:
        return ret;
}

int rate_probe_set_compute_uint(rate_probe_t *probe, uint64_t compute_unit)
{
        int ret;

        ret = sy_rwlock_wrlock(&probe->lock);
        if (ret) {
                GOTO(err_ret, ret);
        }

        probe->unit = compute_unit;

        sy_rwlock_unlock(&probe->lock);

        return 0;
err_ret:
        return ret;
}

static void __rate_probe_update(rate_probe_t *probe)
{
        ytime_t now;

        now = ytime_gettime();
        if (now - probe->useconds > USECONDS_PER_SEC * probe->unit) {
                probe->rate = probe->tally;
                probe->tally = 0;
                probe->useconds = now;
        }
}

int rate_probe_increase(rate_probe_t *probe, uint64_t n)
{
        int ret;

        ret = sy_rwlock_wrlock(&probe->lock);
        if (ret) {
                GOTO(err_ret, ret);
        }
        __rate_probe_update(probe);
        probe->tally += n;

        sy_rwlock_unlock(&probe->lock);

        return 0;
err_ret:
        return ret;
}

int rate_probe_detect(rate_probe_t *probe, uint64_t *rate)
{
        int ret;

        ret = sy_rwlock_wrlock(&probe->lock);
        if (ret) {
                GOTO(err_ret, ret);
        }

        __rate_probe_update(probe);
        *rate =  probe->rate;

        sy_rwlock_unlock(&probe->lock);

        return 0;
err_ret:
        return ret;
}
